package ar.edu.utn.frba.tadp.tp.grupo4.fotomultas.homes;

import java.util.List;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;

import org.uqbar.commons.utils.ApplicationContext;
import org.uqbar.commons.utils.Home;

import ar.edu.utn.frba.tadp.tp.grupo4.fotomultas.capturas.Captura;
import ar.edu.utn.frba.tadp.tp.grupo4.fotomultas.exceptions.EmptyListCapturasException;
import ar.edu.utn.frba.tadp.tp.grupo4.fotomultas.exceptions.PatenteNoReconocidaException;
import ar.edu.utn.frba.tadp.tp.grupo4.fotomultas.externos.ReconocedorDePatentes;
import ar.edu.utn.frba.tadp.tp.grupo4.fotomultas.vehiculos.Vehiculo;

public class AdministradorCapturas {

	private Home<Captura> capturasPendientesHome;
	private Queue<Captura> capturas;

	public AdministradorCapturas() {
		this.capturasPendientesHome = ApplicationContext.getInstance().getHome(
				Captura.class);
		this.capturas = new LinkedList<Captura>();
	}

	public List<Captura> getCapturasPendientes() {
		return this.capturasPendientesHome.getObjects();
	}

	/*
	 * Le env�a la imagen de una captura a un Reconocedor de Patentes para que
	 * nos devuelva la patente. Si no la pudo reconocer, tira una
	 * PatenteNoReconocidaException.
	 */
	public String reconocerPatente(Captura captura,
			ReconocedorDePatentes reconocedorDePatentes) {

		try {

			String patente = reconocedorDePatentes.reconocerPatente(captura
					.getImagen());
			return patente;
		}

		catch (PatenteNoReconocidaException ex) {

			this.capturasPendientesHome.add(captura);
			throw ex;
		}
	}

	/*
	 * Devuelve la siguiente captura pendiente (que hay que reconocerle la
	 * patente de forma manual). Si no hay capturas pendientes, tira un
	 * EmptyListCapturasException.
	 */
	/*
	 * public Captura obtenerCapturaPendiente(){
	 * 
	 * if(!this.capturasPendientesHome.getObjects().isEmpty()){ return
	 * this.capturasPendientesHome.getObjects().get(0); } else throw new
	 * EmptyListCapturasException(); }
	 */
	/*
	 * Como es manual deberia ser una funcion del tipo removerPendiente(Captura)
	 * para que la elimina de las pendientes y la retorna de nuevo para que se
	 * pueda agregar al vehiculo.
	 */
	public Captura removerPendiente(Captura captura) {

		if (captura != null) {
			if (!this.capturasPendientesHome.getObjects().isEmpty()) {
				for (Captura c : this.getCapturasPendientes()) {
					if (c.equals(captura)) {
						this.capturasPendientesHome.remove(c);
						break;
					}
				}
			} else
				throw new EmptyListCapturasException();
		} else
			throw new NullPointerException(
					"No se ha seleccionado una captura para asignar.");

		return captura;
	}

	public void crearBaseInfracciones(Set<Vehiculo> vehiculos) {

		for (Vehiculo veh : vehiculos) {
			List<Captura> capturas = veh.getCapturas();

			for (Captura cap : capturas) {
				this.agregarCaptura(cap);
			}
		}

	}

	/**************** Estadisticas ************************/

	public void agregarCaptura(Captura unaCaptura) {
		this.capturas.add(unaCaptura);
	}

	// Filtro por zona
	public Queue<Captura> obtenerCapturasPorZona(String unaZona) {

		Queue<Captura> capturasQueCumplen = new LinkedList<Captura>();

		for (Captura cap : capturas) {

			if (cap.getZona().getZona().equals(unaZona)) {
				capturasQueCumplen.add(cap);
			}
		}

		return capturasQueCumplen;
	}

	// Filtro por Infraccion
	public Queue<Captura> obtenerCapturasPorInfraccion(String unaInfraccion) {

		Queue<Captura> capturasQueCumplen = new LinkedList<Captura>();

		for (Captura cap : capturas) {

			if (cap.getInfraccion().getTipo().equals(unaInfraccion)) {
				capturasQueCumplen.add(cap);
			}
		}

		return capturasQueCumplen;
	}

	// Filtro por rango horario
	public Queue<Captura> obtenerCapturasPorRangoHorario(int hora1, int hora2) {

		Queue<Captura> capturasQueCumplen = new LinkedList<Captura>();

		for (Captura cap : capturas) {

			int horaCaptura = cap.getFecha().getHourOfDay();

			if (horaCaptura >= hora1 && horaCaptura <= hora2) {
				capturasQueCumplen.add(cap);
			}
		}

		return capturasQueCumplen;
	}

	// Criterios
	public int cantidadDeInfracciones(Queue<Captura> capturas) {

		return capturas.size();
	}

	public int cantidadDePuntos(Queue<Captura> capturas) {
		int puntosTotales = 0;

		for (Captura cap : capturas) {

			puntosTotales += cap.getPuntosInfraccion();
		}
		return puntosTotales;
	}

	public double totalPagado(Queue<Captura> capturas) {

		double totalPagado = 0;

		for (Captura cap : capturas) {
			totalPagado += cap.getMontoPagado();
		}

		return totalPagado;
	}

	public double porcentajePerdonado(Queue<Captura> capturas) {

		double perdonadas = 0;

		for (Captura cap : capturas) {

			if (cap.estaPerdonada()) {
				perdonadas++;
			}
		}

		return perdonadas * 100 / capturas.size();
	}

}
